package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;

import transparent.TransparentScrollPane;
import transparent.TransparentTabbedPane;
import file.FileHandler;
import file.MonitorHandler;
import file.SettingsDefinition;
import file.ValueObject;
import gui.bf3.BF3Setting;

/**
 * This code was edited or generated using CloudGarden's Jigloo SWT/Swing GUI
 * Builder, which is free for non-commercial use. If Jigloo is being used
 * commercially (ie, by a corporation, company or business for any purpose
 * whatever) then you should purchase a license for each developer using Jigloo.
 * Please visit www.cloudgarden.com for details. Use of Jigloo implies
 * acceptance of these licensing terms. A COMMERCIAL LICENSE HAS NOT BEEN
 * PURCHASED FOR THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED LEGALLY FOR
 * ANY CORPORATE OR COMMERCIAL PURPOSE.
 */
public class SettingsGUI extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 8069644835490454485L;
	
	private static final String GOOGLE_CODE_PAGE = "http://code.google.com/p/bf3-settings-tool/";
	private static final String TOOL_NAME = "BF3 Beta Settings Tool - ";
	private static final String VERSION_NUMBER = "0.9";
	
	private static final String SETTING_FILE_NAME = "PROF_SAVE_body";
	
	private static final Dimension WINDOW_SIZE = new Dimension(768, 768);
	private static final Dimension SMALL_WINDOW_SIZE = new Dimension(768, 615);
	
	private static final Color FONT_COLOR = Color.WHITE;


	public URL ICON_URL;
	public URL BACKGROUND_URL;
	
	private Font font;
	private Font boldTitleFont;
	private Font titleFont;

	private JMenuItem saveFile;
	private JMenuItem importFile;
	private JMenuItem exportFile;
	private JMenuItem restoreBackup;
	private JMenuItem exit;
	private JMenuItem about;

	private FileHandler fileHandler;
	private MonitorHandler monitorHandler;
	
	private JFileChooser fc;
	
	private List<ValueObject[]> keysValues;
	private List<BF3Setting> settings;
	
	private String lastOpenedPath;
	private File openConfigFile;
	
	private JPanel backgroundPanel;
	private JScrollPane videoSettingsScrollPane;
	private JScrollPane audioSettingsScrollPane;
	private JScrollPane gameplaySettingsScrollPane;
	

	public static void main(String[] args) {
		setUIDefaults();

		new SettingsGUI();
	}

	private static void setUIDefaults() {
		try {
			UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			System.exit(-1);
		}

		// ######enable transparents for TabbedPaned
		UIManager.put("TabbedPane.contentOpaque", Boolean.FALSE);
		UIManager.put("TabbedPane.tabsOpaque", Boolean.FALSE);
		// #############################

		// ######change font color##########
		UIManager.put("Label.foreground", FONT_COLOR);
		UIManager.put("TitledBorder.titleColor", FONT_COLOR);
		// UIManager.put("TabbedPane.foreground", FONT_COLOR);
		// UIManager.put("ComboBox.foreground", FONT_COLOR);
		// ##################################

		ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
		toolTipManager.setInitialDelay(0);
	}

	private void setUIFonts() {
		UIManager.put("Label.font", font);
		UIManager.put("TabbedPane.font", boldTitleFont);
		UIManager.put("ComboBox.font", font);
		UIManager.put("FormattedTextField.font", font);
		UIManager.put("TitledBorder.font", titleFont);
	}

	public SettingsGUI() {
		loadImages();
		loadFonts();

		settings = new ArrayList<BF3Setting>();

		fileHandler = new FileHandler();
		
		monitorHandler = new MonitorHandler();

		initGUI();

		loadUserConfigFile();

		this.setIconImage(new ImageIcon(ICON_URL).getImage());
		this.setLocationRelativeTo(null);
		this.setResizable(false);
		this.setVisible(true);
	}

	private void loadFonts() {

		try {
			font = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream("/bankgthd.ttf"));
			font = font.deriveFont(12.0F);
			titleFont = font.deriveFont(14.0F);
			boldTitleFont = titleFont.deriveFont(Font.BOLD);
		} catch (FontFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		setUIFonts();

	}

	private void loadImages() {
		ICON_URL = getClass().getResource("/bf3.ico");
		BACKGROUND_URL = getClass().getResource("/BF3_settings.png");
	}

	private void initGUI() {

		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setTitle(TOOL_NAME);
		
		if(monitorHandler.getResolution().height <= WINDOW_SIZE.height){
			this.setSize(SMALL_WINDOW_SIZE);
			this.setMinimumSize(SMALL_WINDOW_SIZE);
			this.setMaximumSize(SMALL_WINDOW_SIZE);
		}
		else{
			this.setSize(WINDOW_SIZE);
			this.setMinimumSize(WINDOW_SIZE);
			this.setMaximumSize(WINDOW_SIZE);
		}
		{
			backgroundPanel = new BackgroundPanel(BACKGROUND_URL);
			BorderLayout backGroundPanelLayout = new BorderLayout();
			backgroundPanel.setLayout(backGroundPanelLayout);
			getContentPane().add(backgroundPanel, BorderLayout.CENTER);
			{
				JTabbedPane settingPanes = new TransparentTabbedPane();
				settingPanes.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, -3, -3, -3));
				backgroundPanel.add(settingPanes, BorderLayout.EAST);
				{
					gameplaySettingsScrollPane = new TransparentScrollPane();
					gameplaySettingsScrollPane.setHorizontalScrollBar(null);
					settingPanes.addTab("Gameplay Settings", null, gameplaySettingsScrollPane, null);
					gameplaySettingsScrollPane.setPreferredSize(new java.awt.Dimension(415, 694));
					{
						gameplaySettingsScrollPane.setViewportView(new GamePlaySettingsPanel(settings));
					}
				}
				{
					audioSettingsScrollPane = new TransparentScrollPane();
					audioSettingsScrollPane.setHorizontalScrollBar(null);
					settingPanes.addTab("Audio Settings", null, audioSettingsScrollPane, null);
					audioSettingsScrollPane.setPreferredSize(new java.awt.Dimension(415, 684));
					{
						audioSettingsScrollPane.setViewportView(new AudioSettingsPanel(settings));
					}
				}
				{
					videoSettingsScrollPane = new TransparentScrollPane();
					videoSettingsScrollPane.setBorder(javax.swing.BorderFactory.createEmptyBorder());
					videoSettingsScrollPane.setHorizontalScrollBar(null);
					settingPanes.addTab("Video Settings", null, videoSettingsScrollPane, null);
					{
						videoSettingsScrollPane.setViewportView(new VideoSettingsPanel(settings));
					}
				}
			}
			{
				backgroundPanel.add(Box.createHorizontalGlue(), BorderLayout.WEST);
			}
		}

		JMenuBar menubar = new JMenuBar();
		JMenu fileMenu = new JMenu("File");
		saveFile = new JMenuItem("Save");
		saveFile.addActionListener(new MenuEntryListener());
		saveFile.setEnabled(false); // Temporarily disabled to avoid Nullpointer
		importFile = new JMenuItem("Import...");
		importFile.addActionListener(new MenuEntryListener());
		exportFile = new JMenuItem("Export...");
		exportFile.addActionListener(new MenuEntryListener());
		exportFile.setEnabled(false); // Temporarily disabled to avoid
										// Nullpointer
		restoreBackup = new JMenuItem("Restore Backup");
		restoreBackup.addActionListener(new MenuEntryListener());
		exit = new JMenuItem("Exit");
		exit.addActionListener(new MenuEntryListener());

		JMenu infoMenu = new JMenu("?");
		about = new JMenuItem("About");
		about.addActionListener(new MenuEntryListener());

		menubar.add(fileMenu);
		fileMenu.add(saveFile);
		fileMenu.add(importFile);
		fileMenu.add(exportFile);
		fileMenu.add(restoreBackup);
		fileMenu.add(exit);
		menubar.add(infoMenu);
		infoMenu.add(about);
		this.setJMenuBar(menubar);

	}

	private void loadUserConfigFile() {
		// initial config loading
		openConfigFile = new File(System.getProperty("user.home") + File.separator + "Documents/Battlefield 3 Open Beta/settings/"
				+ SETTING_FILE_NAME);
		try {
			keysValues = fileHandler.loadFromFile(openConfigFile);
			SettingsDefinition.mapKeysValues(keysValues);
			updateSettingsInGui();
			SettingsGUI.this.setTitle(TOOL_NAME + openConfigFile);

		} catch (FileNotFoundException e) {
			// default file not found, ask to import
			e.printStackTrace();
			importFile.doClick();
		} catch (IOException e) {
			showError(this, "Error while reading setting file. Please select another file or go to " + GOOGLE_CODE_PAGE);
			e.printStackTrace();
		}

		// save/export enabled only when there was loaded something
		if (openConfigFile.exists()) {
			exportFile.setEnabled(true);
			saveFile.setEnabled(true);
		}
	}

	private void updateSettingsInGui() {
		for (BF3Setting setting : settings) {
			setting.updateValue();
		}
	}

	// Listener for Menu Entries Load, Save, Exit
	private class MenuEntryListener implements ActionListener {

		private static final String BAC_FILE_TYPE = ".bac";

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent
		 * )
		 */
		@Override
		public void actionPerformed(ActionEvent e) {
			String ac = e.getActionCommand();

			if (ac.equals("Exit")) {
				System.exit(0);

			} else if (ac.equals("Save")) {
				if (keysValues == null || keysValues.size() == 0) {
					showError(SettingsGUI.this, "No file has been loaded till now. Please load a file first!");
					return;
				}
				if (openConfigFile.exists() && openConfigFile.isFile()
						&& !(new File(openConfigFile.getParent(), openConfigFile.getName() + BAC_FILE_TYPE).exists())) {

					int n = JOptionPane.showOptionDialog(SettingsGUI.this, "There is already a file with the name " + openConfigFile.getName()
							+ ".\nDo you want to make a backup of the old file before saving first?", "Create a backup?", JOptionPane.YES_NO_OPTION,
							JOptionPane.QUESTION_MESSAGE, null, null, null);
					if (n == JOptionPane.YES_OPTION) {
						try {
							fileHandler.createBackup(openConfigFile);
						} catch (FileNotFoundException e1) {
							showError(SettingsGUI.this, "Could not create backup. Sorry! Config will be not be touched.");
							e1.printStackTrace();
							return;
						} catch (IOException e1) {
							showError(SettingsGUI.this, "Could not create backup. Sorry! Config will be not be touched.");
							e1.printStackTrace();
							return;
						}
					}
				}

				try {
					fileHandler.saveToFile(openConfigFile, keysValues);
				} catch (FileNotFoundException e1) {
					// this should not happen
					showError(SettingsGUI.this, "Could not save config file");
					e1.printStackTrace();
					return;
				}
			} else if (ac.equals("Import...")) {

				fc = new JFileChooser();
				// fc.setFileFilter(new FileNameFilter(SETTING_FILE_NAME));
				// fc.setAcceptAllFileFilterUsed(true);

				int returnVal = fc.showOpenDialog(null);

				if (returnVal == JFileChooser.APPROVE_OPTION) {
					try {
						keysValues = fileHandler.loadFromFile(fc.getSelectedFile());
					} catch (FileNotFoundException e1) {
						showError(SettingsGUI.this, "Cannot find selected file!?");
						e1.printStackTrace();
						return;
					} catch (IOException e1) {
						showError(SettingsGUI.this,
								"Error while reading setting file! Please try another config and if the error persist please contact "
										+ GOOGLE_CODE_PAGE);
						e1.printStackTrace();
						return;
					}

					lastOpenedPath = fc.getSelectedFile().getPath();
					openConfigFile = fc.getSelectedFile();

					SettingsGUI.this.setTitle(TOOL_NAME + openConfigFile);

					SettingsDefinition.mapKeysValues(keysValues);
					updateSettingsInGui();

					// save/export enabled only when there was loaded something
					if (openConfigFile.exists()) {
						exportFile.setEnabled(true);
						saveFile.setEnabled(true);
					}
				}

			} else if (ac.equals("Export...")) {
				if (keysValues == null || keysValues.size() == 0) {
					showError(SettingsGUI.this, "No file has been loaded till now. Please load a file first!");
					return;
				}

				if (lastOpenedPath != null) {
					fc = new JFileChooser(lastOpenedPath);
				} else {
					fc = new JFileChooser();
				}

				int returnVal = fc.showSaveDialog(null);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					File selectedFile = fc.getSelectedFile();
					try {
						if (selectedFile.exists() && selectedFile.isFile()
								&& !(new File(selectedFile.getParent(), selectedFile.getName() + BAC_FILE_TYPE).exists())) {
							int n = JOptionPane.showOptionDialog(SettingsGUI.this, "There is already a file with the name " + selectedFile.getName()
									+ ".\nDo you want to make a backup first?", "Create a backup?", JOptionPane.YES_NO_OPTION,
									JOptionPane.QUESTION_MESSAGE, null, null, null);
							if (n == JOptionPane.YES_OPTION) {
								fileHandler.createBackup(selectedFile);
							}
						}
						fileHandler.saveToFile(selectedFile, keysValues);
					} catch (FileNotFoundException e1) {
						showError(SettingsGUI.this, "Could not save the new file!");
						e1.printStackTrace();
						return;
					} catch (IOException e2) {
						showError(SettingsGUI.this, "Could not save the new file!");
						e2.printStackTrace();
						return;
					}
				}
			} else if (ac.equals("Restore Backup")) {
				if (keysValues == null || keysValues.size() == 0) {
					showError(SettingsGUI.this, "No file has been loaded till now. Please load a file first!");
					return;
				}
				File backupFile = new File(openConfigFile.getAbsolutePath() + BAC_FILE_TYPE);
				if (backupFile.exists()) {
					if (!openConfigFile.delete()) {
						showError(SettingsGUI.this, "Failed to delete actuall file to restore backup.");
						return;
					}
					if (!backupFile.renameTo(openConfigFile)) {
						showError(SettingsGUI.this,
								"Failed to rename backup file. Please rename it by yourself! File: " + backupFile.getAbsolutePath());
						return;
					}
				}
			} else if (ac.equals("About")) {
				String message = TOOL_NAME + "Version " + VERSION_NUMBER + "\n\n" + "Copyright 2011 [name of copyright owner]\n" +

				"Licensed under the Apache License, Version 2.0 (the \"License\");\n"
						+ "you may not use this file except in compliance with the License.\n" + "You may obtain a copy of the License at\n\n" +

						"    http://www.apache.org/licenses/LICENSE-2.0\n\n" +

						"Unless required by applicable law or agreed to in writing, software\n"
						+ "distributed under the License is distributed on an \"AS IS\" BASIS,\n"
						+ "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
						+ "See the License for the specific language governing permissions and\n" + "limitations under the License.";
				JOptionPane.showMessageDialog(SettingsGUI.this, message, "Info", JOptionPane.INFORMATION_MESSAGE);
			}
		}

	}

	public static void showError(Component component, String message) {
		JOptionPane.showMessageDialog(component, message, "Error", JOptionPane.ERROR_MESSAGE);
	}
}
